package com.pi.shisan.web.controller;

import com.pi.shisan.service.audio.AudioPlayer;
import com.pi.shisan.service.audio.MixPlayer;
import com.pi.shisan.service.dto.FileDTO;
import com.pi.shisan.service.dto.Result;
import com.pi.shisan.service.util.ReflectUtil;
import com.pi.shisan.util.FileUtils;
import com.pi.shisan.web.util.FormatConvert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/file_manager")
@Slf4j
public class UploadFileController {

    @PostMapping("/upload")
    public Result<Void> uploadFile (@RequestParam("file") MultipartFile file) throws Exception{
        //临时存储目录
        new File("music").mkdirs();
        File dir = new File("tmp_files");
        dir.mkdirs();
        String fileName = file.getOriginalFilename();
        FileDTO fileDTO = new FileDTO();
        fileDTO.setFileName(fileName);
        if (checkFileExists(fileDTO).getData()) {
            return Result.err("文件已存在");
        }
        File targetFile = new File("music/"+fileName);

        InputStream inputStream = file.getInputStream();
        File ioFile = null;
        if (inputStream instanceof FileInputStream) {
            try {
                Field pathField = ReflectUtil.getField(inputStream.getClass(),"path");
                if (pathField != null) {
                    pathField.setAccessible(true);
                    String path = (String) pathField.get(inputStream);
                    if (path != null) {
                        ioFile = new File(path);
                    }
                }
            } catch (Exception e) {
            }
        }
        if (ioFile == null) {
            ioFile = new File(dir.getPath() + "/" + UUID.randomUUID().toString().replaceAll("-","")+"."+ FileUtils.getFileNameSuffix(fileName));
            FileOutputStream fos = new FileOutputStream(ioFile);
            boolean hasErr = false;
            try {
                byte[] data = new byte[2048];
                int len;
                while ((len = inputStream.read(data)) > 0) {
                    fos.write(data,0,len);
                }
                fos.flush();
            } catch (Exception e) {
                hasErr = true;
                log.error("上传文件时copy失败：{}",file.getOriginalFilename(), e);
                throw e;
            } finally {
                try {
                    fos.close();
                } catch (Exception e) {
                }
                try {
                    inputStream.close();
                } catch (Exception e) {}
                if (hasErr) {
                    FileUtils.tryToFocusDeleteFileAsync(ioFile);
                }
            }
        }
        try {
            readIsCouldPlayFile(ioFile, FileUtils.getFileNameSuffix(file.getOriginalFilename()));
        } catch (Exception e) {
            try {
                targetFile = new File(targetFile.getParent()+"/"+FileUtils.getFileNameWithoutSuffix(targetFile.getName())+".mp3");
                FormatConvert.convertToMp3(ioFile, targetFile);
                FileUtils.tryToFocusDeleteFile(ioFile);
                return Result.ok();
            } catch (Exception ex) {
                log.error("上传音频读取音频内容失败[外]：{}",file.getOriginalFilename(),e);
                log.error("上传音频读取音频内容失败[内]：{}",file.getOriginalFilename(),ex);
                return Result.err("这可能不是一个有效的音频文件");
            }
        }
        try {
            FileUtils.copyFile(new FileInputStream(ioFile), new FileOutputStream(targetFile));
        } finally {
            FileUtils.tryToFocusDeleteFile(ioFile);
        }

        return Result.ok();
    }

    @GetMapping("/file-list")
    public Result<List<FileDTO>> allMusicFiles() {
        File[] files = new File("music").listFiles();
        if (files == null) {
            return Result.ok();
        }
        List<FileDTO> fileList = new ArrayList<>(files.length);
        FileDTO fileDTO;
        for (File file : files) {
            if (file.isDirectory()) {
                continue;
            }
            fileDTO = new FileDTO();
            fileDTO.setFileName(file.getName());
            fileDTO.setPath(file.getPath());
            fileDTO.setLength(file.length());
            fileList.add(fileDTO);
        }
        return Result.ok(fileList);
    }

    @PostMapping("/check-exists")
    public Result<Boolean> checkFileExists(@RequestBody FileDTO fileDTO) {
        if (fileDTO.getFileName() == null) {
            return Result.err("请指定文件");
        }
        File file = new File("music/" + fileDTO.getFileName());
        String fileName = fileDTO.getFileName();
        if (file.exists()) {
            return Result.ok(true);
        } else {
            if (!"mp3".equalsIgnoreCase(FileUtils.getFileNameSuffix(fileName))) {
                File tmpFile = new File(file.getParent()+"/"+FileUtils.getFileNameWithoutSuffix(fileName)+".mp3");
                return Result.ok(tmpFile.exists());
            }
        }
        return Result.ok(false);
    }

    @PostMapping("/delete-file")
    public Result<Void> deleteFile(@RequestBody FileDTO fileDTO) {
        if (fileDTO.getPath() == null) {
            return Result.err("请指定文件");
        }
        File targetFile = new File(fileDTO.getPath());
        String filePath = targetFile.getAbsolutePath().replaceAll("\\\\","/");
        File acceptDir = new File("music/");
        if (!filePath.startsWith(acceptDir.getAbsolutePath().replaceAll("\\\\","/"))) {
            return Result.err("无权操作");
        }
        FileUtils.tryToFocusDeleteFile(targetFile);
        if (targetFile.exists()) {
            return Result.err("删除失败");
        }
        return Result.ok();
    }

    private void readIsCouldPlayFile(File file, String suffix) throws Exception{
        AudioPlayer player = new MixPlayer(file, suffix,null);
        if (player.getTotalMilliseconds() <= 0) {
            throw new RuntimeException("可能不是一个有效音频");
        }
        player.destroy();
    }

}
